/*
 * TesterMain.cpp
 *
 *  Created on: Jan 7, 2011
 *      Author: dt
 */



/*
 * Jingle call example
 * Copyright 2004--2005, Google Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Tempe Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <iomanip>
#include <time.h>
#include <pthread.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>

#ifndef WIN32
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <iomanip>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/wait.h>
//#include "talk/examples/monarch-client/monarchTester/joystick.pb.h"

#else
#include <direct.h>
//typedef _getcwd getcwd;
#include "talk/base/win32.h"
#endif


#include "talk/examples/monarch-common/XMPPCallback.h"
//#include "talk/session/phone/filemediaengine.h"

#include "talk/examples/monarch-common/monarchController.h"

#include "talk/base/flags.h"
#include "talk/base/thread.h"

#include "monarchmediaengine.h"

#include "TesterMain.h"


const char* MONARCH_VIDEO_IN_PIPE = "/tmp/monarch-video-in.pipe";
const char* MONARCH_VIDEO_OUT_PIPE = "/tmp/monarch-video-out.pipe";

const char* MONARCH_VOICE_IN_PIPE = "/tmp/monarch-voice-in.pipe";
const char* MONARCH_VOICE_OUT_PIPE = "/tmp/monarch-voice-out.pipe";

const char* MONARCH_CMD_IN_PIPE = "/tmp/monarch-cmd-in.pipe";
const char* MONARCH_CMD_OUT_PIPE = "/tmp/monarch-cmd-out.pipe";



TesterMain::TesterMain(std::string& username, std::string& password,  std::string& xmppServerAddress, bool& debug , unsigned int& msgsize, unsigned int& msginterval,
    cricket::MediaEngine& mediaEngine,
    std::string& cmd_in, std::string& cmd_out)
{
  msgsize_ = msgsize;
  msginterval_ = msginterval;
  media_engine_ = &mediaEngine;


  tunnel_connected_ = false;
  read_buf_len_ =0;

  monarch_controller_ = new MonarchController( this , username, password, xmppServerAddress, debug,media_engine_);
  monarch_controller_->start();

}


cricket::MediaEngine* CreateMonarchClientMediaEngine(const char* voice_in,
                                            const char* voice_out,
                                            const char* video_in,
                                            const char* video_out) {
  cricket::MonarchMediaEngine* monarch_media_engine = new cricket::MonarchMediaEngine;
  // Set the RTP dump file names.
  if (voice_in) {
    monarch_media_engine->set_voice_input_filename(voice_in);
  }
  if (voice_out) {
    monarch_media_engine->set_voice_output_filename(voice_out);
  }
  if (video_in) {
    monarch_media_engine->set_video_input_filename(video_in);
  }
  if (video_out) {
    monarch_media_engine->set_video_output_filename(video_out);
  }

  // Set voice and video codecs. TODO: The codecs actually depend on
  // the the input voice and video streams.
  std::vector<cricket::AudioCodec> voice_codecs;
  voice_codecs.push_back(
      cricket::AudioCodec(0, "PCMU", 8000, 0, 1, 0));
  monarch_media_engine->set_voice_codecs(voice_codecs);

  std::vector<cricket::VideoCodec> video_codecs;
  video_codecs.push_back(
      cricket::VideoCodec(26, "JPEG", 640, 480, 16, 0));
  monarch_media_engine->set_video_codecs(video_codecs);

  return monarch_media_engine;
}



void TesterMain::onRosterAdd(std::string& username)
{
  std::cout << "ROSTER UPDATED " <<  username << " \n" ;
  if(msgsize_){
    monarch_controller_->requestTunnelTo(username, this);
  }

}


void TesterMain::sendCommands(void *threadid)
{

       int writeResult;

       /* write to the pipe */

       if(read_buf_len_>0 && tunnel_connected_)
       {
         writeResult = pipe_->WriteToStream(read_buf_, read_buf_len_);
         if(writeResult != true)
         {
           printf("write to libjingle stream failed! %i \n", writeResult);
         }
         else
         {
             read_buf_len_=0;
         }
       }
}

void TesterMain::handlePBUFMSG(char* pbuf, int len)
{

       read_buf_[0] = 62;
       read_buf_[1] = 62;
       read_buf_[2] = 62;

       read_buf_[3] = (char) len/256;
       read_buf_[4] = (char) len%256;

       memcpy(read_buf_+5,pbuf,len);

       read_buf_[len+5] = 60;
       read_buf_[len+6] = 60;
       read_buf_[len+7] = 60;

       int writeResult;

       read_buf_len_ = len+8;

       PostDelayed(10, this);
}


void TesterMain::onXmppConnected()
{
  std::cout << "XMPP CONNECTED\n";
}


ConnectionCallback* TesterMain:: onIncomingTunnelRequest()
{
  //always accept requests
  return this;
}

void TesterMain:: onChatMessageReceived(std::string& from, std::string& msg)
{
  std::cout << from << " says: "<< msg << std::endl;
}

//start sending data if we are are the src
void TesterMain::onTunnelConnect(PipeEp* p)
{


  std::cout << "TUNNEL CONNECTED OK\n";
  pipe_ = p;
    int ret_val;
       /* Create the named - pipe */

   // std::cout << "opening named pipe for commands\n";
    //   ret_val = mkfifo(MONARCH_CMD_IN_PIPE, 0666);

    //   if ((ret_val == -1) && (errno != EEXIST)) {
     //      perror("Error creating the named pipe");
      //     exit(1);
      // }

   /* Open the pipe for reading */
    //rcv_pipe_ = open(MONARCH_CMD_IN_PIPE, O_RDONLY);
    //std::cout << "Success\n";

    tunnel_connected_ = true;

    // Start this thread
   Thread::Start();
   // PostDelayed(100, this);
}

void TesterMain:: onTunnelDisconnect(PipeEp* p, bool withError)
{
  tunnel_connected_ = false;

}

void TesterMain::onDataRecive(PipeEp* p, const char* buf, size_t size)
{

}


void TesterMain::OnMessage(talk_base::Message* pmsg) {
    if (!tunnel_connected_) {
        return;
    }
    sendCommands(NULL);
   // PostDelayed(50, this);
   // Quit();
}




void function( int sig){
  printf("Got SIGABORT: %d", sig);
  getchar();
  exit(0);
}

int main(int argc, char **argv) {

  signal( SIGABRT, function);
  // define options
  DEFINE_bool(a, false, "Turn on auto accept.");
  DEFINE_bool(d, false, "Turn on debugging.");
  DEFINE_int(msgsize, 0, "Automatically start a test connection and send packets of this size");
  DEFINE_int(msginterval, 100, "Interval Between Sent Packets.");
  DEFINE_bool(testserver, false, "Use test server");
  DEFINE_int(portallocator, 0, "Filter out unwanted connection types.");
  DEFINE_string(filterhost, NULL, "Filter out the host from all candidates.");
  DEFINE_string(s, "talk.google.com", "The connection server to use.");
  DEFINE_bool(help, false, "Prints this message");

  DEFINE_bool(plainserver, false, "Turn off tls and allow plain password.");
  DEFINE_string(voiceinput, NULL, "RTP dump file for voice input.");
  DEFINE_string(voiceoutput, NULL, "RTP dump file for voice output.");
  DEFINE_string(videoinput, NULL, "RTP dump file for video input.");
  DEFINE_string(videooutput, NULL, "RTP dump file for video output.");
  DEFINE_bool(debugsrtp, false, "Enable debugging for srtp.");

  DEFINE_string(cmdinput, NULL, "Pipe for protbuff formated command input.");
  DEFINE_string(cmdoutput, NULL, "Pipe for protbuff formated command output.");

  // parse options
  FlagList::SetFlagsFromCommandLine(&argc, argv, true);
  if (FLAG_help)
    {
      FlagList::Print(NULL, false);
      return 0;
    }

  //bool auto_accept = FLAG_a;
  bool debug = FLAG_d;
  unsigned int msgsize = (unsigned int) FLAG_msgsize;
  unsigned int msginterval = (unsigned int) FLAG_msginterval;
  bool test_server = FLAG_testserver;
  int32 portallocator_flags = FLAG_portallocator;
  std::string server = FLAG_s;


  /*
  bool auto_accept = FLAG_a;
  //std::string protocol = FLAG_protocol;
  bool plain_server = FLAG_plainserver;
  //std::string secure = FLAG_secure;
  bool debugsrtp = FLAG_debugsrtp;

  if (debugsrtp) {
    cricket::EnableSrtpDebugging();
  }

  cricket::SignalingProtocol initial_protocol = cricket::PROTOCOL_HYBRID;
  if (protocol == "jingle") {
    initial_protocol = cricket::PROTOCOL_JINGLE;
  } else if (protocol == "gingle") {
    initial_protocol = cricket::PROTOCOL_GINGLE;
  } else if (protocol == "hybrid") {
    initial_protocol = cricket::PROTOCOL_HYBRID;
  } else {
    println("Invalid protocol.  Must be jingle, gingle, or hybrid.\n");
    return 1;
  }

  cricket::SecureMediaPolicy secure_policy = cricket::SEC_ENABLED;
  if (secure == "disable") {
    secure_policy = cricket::SEC_DISABLED;
  } else if (secure == "enable") {
    secure_policy = cricket::SEC_ENABLED;
  } else if (secure == "require") {
    secure_policy = cricket::SEC_REQUIRED;
  } else {
      println("Invalid encryption.  Must be enable, disable, or require.\n");
    return 1;
  }
*/
  // parse username and password, if present
  std::string username;
  std::string password = "";

  std::string xmppServerAddress;
  if (argc > 1)
    {
      username = argv[1];
      if (argc > 2)
        {
          password = argv[2];
        }
    }


  if (username.empty())
    {
      std::cout << "YOUR JID: ";
      std::cin >> username;
    }

  if (password.empty() && !test_server)
    {
      //Console::SetEcho(false);
      std::cout << "Password: ";
      std::cin >>  password;
      //Console::SetEcho(true);
      std::cout << std::endl;
    }

  //printf("Logging in to %s as %s\n", server.c_str(), jid.Str().c_str());


  cricket::MediaEngine* engine = NULL;

  if (FLAG_voiceinput || FLAG_voiceoutput || FLAG_videoinput || FLAG_videooutput) {
    engine = CreateMonarchClientMediaEngine(FLAG_voiceinput, FLAG_voiceoutput, FLAG_videoinput, FLAG_videooutput);
  }
  else
  {
    engine = CreateMonarchClientMediaEngine(NULL,MONARCH_VOICE_OUT_PIPE,NULL,MONARCH_VIDEO_OUT_PIPE);
  }

  //engine = CreateFileMediaEngine("/tmp/voice.rtpdump", "/tmp/adump", NULL ,NULL);


  std::string cmd_in = MONARCH_CMD_IN_PIPE;
  std::string cmd_out = MONARCH_CMD_OUT_PIPE;

  XMPPCallback *xmppCallback = new TesterMain( username, password, server, debug, msgsize, msginterval,
      *engine,
      cmd_in,
      cmd_out);

  xmppCallback = NULL;

  return 0;
}
